import time
import re

from PyQt5.QtCore import QEventLoop, QTimer
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QStyleFactory, QMessageBox
from common.common import Common


class ShowTabMotorDriver:
    def __init__(self, ui, ptr):
        self.ui = ui
        self.ptr = ptr
        self.park_model_control = None
        self.left_reset_model_control = None
        self.right_reset_model_control = None
        self.left_driver_model_show = None
        self.left_driver_model_control = None
        self.right_driver_model_show = None
        self.right_driver_model_control = None

    def init_ui(self):
        self.init_tab_motor_group_park()
        self.init_tab_motor_group_left_reset()
        self.init_tab_motor_group_right_reset()
        self.init_tab_motor_group_left_wheel()
        self.init_tab_motor_group_right_wheel()
        self.ui.lineEdit_valid_num.setPlaceholderText("有效值1-7")
        self.init_connect()
        self.ui.lineEdit_para_loop.setText("0")
        pass

    def init_connect(self):
        self.ui.pushButton_left_speed_control.clicked.connect(
            lambda: self.btn_left_wheel_control_clicked("left wheel"))
        self.ui.pushButton_right_speed_control.clicked.connect(
            lambda: self.btn_right_wheel_control_clicked("right wheel"))
        self.ui.pushButton_left_dece_acce_control.clicked.connect(
            lambda: self.btn_left_dec_acc_control_clicked("left_dec_acc"))
        self.ui.pushButton_right_dece_acce_control.clicked.connect(
            lambda: self.btn_right_dec_acc_control_clicked("right_dec_acc"))
        self.ui.pushButton_park_control.clicked.connect(
            lambda: self.btn_park_control_clicked("park control"))
        self.ui.pushButton_left_wheel_reset.clicked.connect(
            lambda: self.btn_left_wheel_reset_clicked("left reset"))
        self.ui.pushButton_right_wheel_reset.clicked.connect(
            lambda: self.btn_right_wheel_reset_clicked("right reset"))
        self.ui.pushButton_send_test_para.clicked.connect(
            lambda: self.btn_send_test_para_clicked("send test para"))
        self.ui.pushButton_stop_bow_test.clicked.connect(
            lambda: self.btn_stop_bow_test_clicked("stop bow test"))
        self.ui.pushButton_left_dece_acce_control.setEnabled(False)
        self.ui.pushButton_right_dece_acce_control.setEnabled(False)

    @staticmethod
    def get_data_h_l(dec_data: int):
        h_data = Common.get_hex_data_h(dec_data)
        l_data = Common.get_hex_data_l(dec_data)
        return [h_data, l_data]

    def out_input_scope(self,  num_str: str, speed_min: int, speed_max: int):
        is_invalid_para = False
        num = float(num_str)
        if num > speed_max or num < speed_min:
            QMessageBox.warning(self.ptr, "Error", "超过数字范围" + str(speed_min) + "-" + str(speed_max), QMessageBox.Cancel)
            is_invalid_para = True
        return is_invalid_para

    def is_invalid_input(self, in_str: str):
        is_invalid_input = False
        if not in_str:
            QMessageBox.warning(self.ptr, "Error", "编辑框内无输入！", QMessageBox.Cancel)
            is_invalid_input = True
        elif re.search(r'[a-zA-Z]', in_str) is not None:
            QMessageBox.warning(self.ptr, "Error", "输入不支持字母！", QMessageBox.Cancel)
            is_invalid_input = True
        elif re.search(r'[!@#$%^&*(),?":{}|<>]', in_str) is not None:
            QMessageBox.warning(self.ptr, "Error", "输入不支持特殊字符！", QMessageBox.Cancel)
            is_invalid_input = True
        elif re.search(r'[\u4e00-\u9fff]', in_str) is not None:
            QMessageBox.warning(self.ptr, "Error", "输入不支持汉字！", QMessageBox.Cancel)
            is_invalid_input = True
        return is_invalid_input

    def show_ui_item(self, n, is_show: bool):
        n = n + 1
        for i in range(n, 8):
            getattr(self.ui, "lineEdit_para" + str(i) + "_left").setEnabled(is_show)
            getattr(self.ui, "lineEdit_para" + str(i) + "_right").setEnabled(is_show)
            getattr(self.ui, "lineEdit_para" + str(i) + "_time").setEnabled(is_show)

    def is_invalid_para(self, n):
        is_invalid_para = False
        for i in range(1, n + 1):
            left_str = getattr(self.ui, "lineEdit_para" + str(i) + "_left").text()
            if self.is_invalid_input(left_str) or self.out_input_scope(left_str, -2, 2):
                is_invalid_para = True
                break
            # v_left = float(left_str)
            # if v_left > 2 or v_left < -2:
            #     QMessageBox.warning(self.ptr, "Error", "只支持数字-2-2", QMessageBox.Cancel)
            #     is_invalid_para = True
            #     return is_invalid_para
            right_str = getattr(self.ui, "lineEdit_para" + str(i) + "_right").text()
            if self.is_invalid_input(right_str) or self.out_input_scope(right_str, -2, 2):
                is_invalid_para = True
                break
            # v_right = float(right_str)
            # if v_right > 2 or v_right < -2:
            #     QMessageBox.warning(self.ptr, "Error", "只支持数字-2-2", QMessageBox.Cancel)
            #     is_invalid_para = True
            #     return is_invalid_para
            time_str = getattr(self.ui, "lineEdit_para" + str(i) + "_time").text()
            if self.is_invalid_input(time_str):
                is_invalid_para = True
                break
            time_int = int(time_str)
            if time_int > 30 * 1000 or time_int <= 0:
                QMessageBox.warning(self.ptr, "Error", "只支持数字0-30000", QMessageBox.Cancel)
                is_invalid_para = True
                break
        return is_invalid_para

    def btn_stop_bow_test_clicked(self, info):
        print(info)
        Common().set_bow_test_loop(False)
        pass

    def btn_send_test_para_clicked(self, info):
        print(info)
        num_str = self.ui.lineEdit_valid_num.text()
        if self.is_invalid_input(num_str) or self.out_input_scope(num_str, 1, 7):
            return
        num = int(num_str)
        if self.is_invalid_para(num):
            return
        self.show_ui_item(num, False)
        num_loop = int(self.ui.lineEdit_para_loop.text())
        j = 0
        while j < 2 * num_loop:
            for i in range(1, num + 1):
                left_speed_str = getattr(self.ui, "lineEdit_para" + str(i) + "_left").text()
                n = int((60 * 36 * float(left_speed_str)) // (3.14 * 325 * 0.001))
                list_h_l_left = self.get_data_h_l(n)
                right_speed_str = getattr(self.ui, "lineEdit_para" + str(i) + "_right").text()
                n = int((60 * 36 * float(right_speed_str)) // (3.14 * 325 * 0.001))
                list_h_l_right = self.get_data_h_l(n)
                time_str = getattr(self.ui, "lineEdit_para" + str(i) + "_time").text()
                time_int = int(time_str)
                if len(list_h_l_left) == 0 or len(list_h_l_right) == 0:
                    self.show_ui_item(num, True)
                    return
                if Common().is_init_connect() is None:
                    QMessageBox.warning(self.ptr, "Error", "连接未初始化，别试了", QMessageBox.Cancel)
                    self.show_ui_item(num, True)
                    return
                if not Common().get_bow_test_loop():
                    j = num_loop * 2
                    Common().set_bow_test_loop(True)
                    break
                Common().send_data(0x224, [0xA5, 0x01, 0x3C, 0x02,
                                           list_h_l_left[1], list_h_l_left[0],
                                           list_h_l_right[1], list_h_l_right[0]])
                loop = QEventLoop()
                QTimer.singleShot(time_int, loop.quit)  # 3秒后退出事件循环
                loop.exec_()
                j = j + 1
        # stop
        Common().send_data(0x224, [0xA5, 0x01, 0x3C, 0x02, 0X00, 0x00, 0x00, 0x00])
        self.show_ui_item(num, True)
        pass

    def btn_park_control_clicked(self, info):
        print(info)
        value_str = self.park_model_control.item(0).child(0, 1).text()
        try:
            value_i = int(value_str)
            if value_i == 1:
                Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x27, 0x02, 0x01, 0x00, 0x00, 0xA5])
            elif value_i == 0:
                Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x27, 0x02, 0x00, 0x00, 0x00, 0xA5])
            else:
                QMessageBox.warning(self.ptr, "Error", "非法输入值，只接受0，1", QMessageBox.Cancel)
        except Exception as e:
            print(e)
            QMessageBox.warning(self.ptr, "Error", "非法输入值，只接受数字", QMessageBox.Cancel)

    def btn_left_wheel_control_clicked(self, info):
        print(info)
        left_speed_str = self.ui.lineEdit_left_speed.text()
        if self.is_invalid_input(left_speed_str) or self.out_input_scope(left_speed_str, -2, 2):
            return
        # left_speed_str = self.left_driver_model_control.item(0).child(0, 1).text()
        n = (60 * 36 * float(left_speed_str)) // (3.14 * 325 * 0.001)
        n = int(n)
        list_h_l = self.get_data_h_l(n)
        if list_h_l is None:
            return
        if Common().get_can_bus() is None:
            QMessageBox.warning(self.ptr, "Error", "CAN没初始化，别试了", QMessageBox.Cancel)
            return
        Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x21, 0x02, list_h_l[1], list_h_l[0], 0x00, 0xA5])

    def btn_left_dec_acc_control_clicked(self, info):
        print(info)
        left_dec_str = self.ui.lineEdit_left_deceleration.text()
        left_acc_str = self.ui.lineEdit_left_acceleration.text()
        if self.is_invalid_input(left_dec_str) or self.out_input_scope(left_dec_str, 0, 4250):
            return
        elif self.is_invalid_input(left_acc_str) or self.out_input_scope(left_acc_str, 0, 4250):
            return
        if Common().is_init_connect():
            QMessageBox.warning(self.ptr, "Error", "连接失败或未连接，别试了", QMessageBox.Cancel)
            return
        n = int(left_dec_str)
        list_h_l_dec = self.get_data_h_l(n)
        n = int(left_acc_str)
        list_h_l_acc = self.get_data_h_l(n)
        if list_h_l_dec or list_h_l_acc is None:
            return
        Common().send_data(0x224, [0xA5, 0x01, 0x3D, 0x02,
                                   list_h_l_acc[1], list_h_l_acc[0],
                                   list_h_l_dec[1], list_h_l_dec[0]])
        pass

    def btn_right_dec_acc_control_clicked(self, info):
        print(info)
        left_dec_str = self.ui.lineEdit_right_deceleration.text()
        left_acc_str = self.ui.lineEdit_right_acceleration.text()
        if self.is_invalid_input(left_dec_str) or self.out_input_scope(left_dec_str, 0, 4250):
            return
        elif self.is_invalid_input(left_acc_str) or self.out_input_scope(left_acc_str, 0, 4250):
            return
        if Common().is_init_connect():
            QMessageBox.warning(self.ptr, "Error", "连接失败或未连接，别试了", QMessageBox.Cancel)
            return
        n = int(left_dec_str)
        list_h_l_dec = self.get_data_h_l(n)
        n = int(left_acc_str)
        list_h_l_acc = self.get_data_h_l(n)
        if list_h_l_dec or list_h_l_acc is None:
            return
        Common().send_data(0x224, [0xA5, 0x01, 0x3E, 0x02,
                                   list_h_l_acc[1], list_h_l_acc[0],
                                   list_h_l_dec[1], list_h_l_dec[0]])
        pass

    def btn_right_wheel_control_clicked(self, info):
        print(info)
        # right_speed_str = self.right_driver_model_control.item(0).child(0, 1).text()
        right_speed_str = self.ui.lineEdit_right_speed.text()
        if self.is_invalid_input(right_speed_str) or self.out_input_scope(right_speed_str, -2, 2):
            return
        n = (60 * 36 * float(right_speed_str)) // (3.14 * 325 * 0.001)
        n = int(n)
        list_h_l = self.get_data_h_l(n)
        if list_h_l is None:
            return
        if Common().get_can_bus() is None:
            QMessageBox.warning(self.ptr, "Error", "CAN没初始化，别试了", QMessageBox.Cancel)
            return
        Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x22, 0x02, list_h_l[1], list_h_l[0], 0x00, 0xA5])

    def btn_left_wheel_reset_clicked(self, info):
        print(info)
        left_reset_str = self.left_reset_model_control.item(0).child(0, 1).text()
        value_i = int(left_reset_str)
        if value_i == 0:  # white
            Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x36, 0x02, 0x00, 0x00, 0x00, 0xA5])
        elif value_i == 1:  # red
            Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x36, 0x02, 0x01, 0x00, 0x00, 0xA5])
        else:
            QMessageBox.warning(self.ptr, "Error", "非法输入值，只接受0-1", QMessageBox.Cancel)

    def btn_right_wheel_reset_clicked(self, info):
        print(info)
        right_reset_str = self.right_reset_model_control.item(0).child(0, 1).text()
        value_i = int(right_reset_str)
        if value_i == 0:  # white
            Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x37, 0x00, 0x01, 0x00, 0x00, 0xA5])
        elif value_i == 1:  # red
            Common().get_can_bus().send_data(0x224, [0xA5, 0x01, 0x37, 0x01, 0x02, 0x00, 0x00, 0xA5])
        else:
            QMessageBox.warning(self.ptr, "Error", "非法输入值，只接受0-1", QMessageBox.Cancel)

    @staticmethod
    def init_tree_park_control(model):
        # set item
        item = QStandardItem('控制')
        model.appendRow(item)
        # model.setItem(0, 1, QStandardItem('[Object]'))
        # 添加子条目
        item_child = QStandardItem('驻车(0开1关)')
        item.appendRow(item_child)
        item.setChild(0, 1, QStandardItem('[Object]'))

    def init_tab_motor_group_park(self):
        self.park_model_control = QStandardItemModel(self.ptr)
        self.park_model_control.setHorizontalHeaderLabels(['item', 'value'])

        self.init_tree_park_control(self.park_model_control)
        self.ui.treeView_park_control.setModel(self.park_model_control)
        # 调整第一列的宽度
        self.ui.treeView_park_control.header().resizeSection(0, 180)
        self.ui.treeView_park_control.header().resizeSection(1, 70)
        # 设置成有虚线连接的方式
        self.ui.treeView_park_control.setStyle(QStyleFactory.create('windows'))
        # 完全展开
        self.ui.treeView_park_control.expandAll()

    @staticmethod
    def init_tree_left_reset_control(model):
        # set item
        item = QStandardItem('控制')
        model.appendRow(item)
        # model.setItem(0, 1, QStandardItem('[Object]'))
        # 添加子条目
        item_child = QStandardItem('左轮复位(0复位)')
        item.appendRow(item_child)
        item.setChild(0, 1, QStandardItem('[Object]'))

    def init_tab_motor_group_left_reset(self):
        self.left_reset_model_control = QStandardItemModel(self.ptr)
        self.left_reset_model_control.setHorizontalHeaderLabels(['item', 'value'])

        self.init_tree_left_reset_control(self.left_reset_model_control)
        self.ui.treeView_left_wheel_reset.setModel(self.left_reset_model_control)
        # 调整第一列的宽度
        self.ui.treeView_left_wheel_reset.header().resizeSection(0, 200)
        self.ui.treeView_left_wheel_reset.header().resizeSection(1, 70)
        # 设置成有虚线连接的方式
        self.ui.treeView_left_wheel_reset.setStyle(QStyleFactory.create('windows'))
        # 完全展开
        self.ui.treeView_left_wheel_reset.expandAll()

    @staticmethod
    def init_tree_right_reset_control(model):
        # set item
        item = QStandardItem('控制')
        model.appendRow(item)
        # model.setItem(0, 1, QStandardItem('[Object]'))
        # 添加子条目
        item_child = QStandardItem('右轮复位(0复位)')
        item.appendRow(item_child)
        item.setChild(0, 1, QStandardItem('[Object]'))

    def init_tab_motor_group_right_reset(self):
        self.right_reset_model_control = QStandardItemModel(self.ptr)
        self.right_reset_model_control.setHorizontalHeaderLabels(['item', 'value'])

        self.init_tree_right_reset_control(self.right_reset_model_control)
        self.ui.treeView_right_wheel_reset.setModel(self.right_reset_model_control)
        # 调整第一列的宽度
        self.ui.treeView_right_wheel_reset.header().resizeSection(0, 200)
        self.ui.treeView_right_wheel_reset.header().resizeSection(1, 70)
        # 设置成有虚线连接的方式
        self.ui.treeView_right_wheel_reset.setStyle(QStyleFactory.create('windows'))
        # 完全展开
        self.ui.treeView_right_wheel_reset.expandAll()

    # @staticmethod
    # def init_tree_left_wheel_control(model):
    #     item = QStandardItem('控制')
    #     model.appendRow(item)
    #     # 添加子条目
    #     item_child = QStandardItem('速度m/s')
    #     item.appendRow(item_child)
    #     item_child.setEditable(False)
    #     item.setChild(0, 1, QStandardItem(str(0)))
    #     # 添加子条目
    #     item_child = QStandardItem('运行周期s')
    #     item.appendRow(item_child)
    #     item.setChild(1, 1, QStandardItem(str(0)))
    #     item.child(1, 1).setEnabled(False)
    #     pass

    @staticmethod
    def init_tree_left_wheel_show(model):
        item = QStandardItem('左驱动轮状态')
        model.appendRow(item)
        # model.setItem(0, 1, QStandardItem('[Object]'))

        # 添加子条目
        # item_child = QStandardItem('转向(0反1正)')
        # item.appendRow(item_child)
        # item.setChild(0, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('速度m/s')
        item.appendRow(item_child)
        item.setChild(0, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('电流mA')
        item.appendRow(item_child)
        item.setChild(1, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('扭矩')
        item.appendRow(item_child)
        item.setChild(2, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('里程计')
        item.appendRow(item_child)
        item.setChild(3, 1, QStandardItem('0'))

        # 添加子条目
        item_child = QStandardItem('错误代码')
        item.appendRow(item_child)
        item.setChild(4, 1, QStandardItem('[Object]'))
        pass

    def init_tab_motor_group_left_wheel(self):
        self.left_driver_model_control = QStandardItemModel(self.ptr)
        self.left_driver_model_control.setHorizontalHeaderLabels(['item', 'value'])
        self.left_driver_model_show = QStandardItemModel(self.ptr)
        self.left_driver_model_show.setHorizontalHeaderLabels(['item', 'value'])
        # self.init_tree_left_wheel_control(self.left_driver_model_control)
        self.init_tree_left_wheel_show(self.left_driver_model_show)
        # self.ui.treeView_left_wheel_control.setModel(self.left_driver_model_control)
        self.ui.treeView_left_wheel_show.setModel(self.left_driver_model_show)
        # 调整第一列的宽度
        # self.ui.treeView_left_wheel_control.header().resizeSection(0, 160)
        # self.ui.treeView_left_wheel_control.header().resizeSection(1, 70)
        self.ui.treeView_left_wheel_show.header().resizeSection(0, 160)
        self.ui.treeView_left_wheel_show.header().resizeSection(1, 70)
        # windows_style = QStyleFactory.create('windows')
        # 设置成有虚线连接的方式
        # self.ui.treeView_left_wheel_control.setStyle(QStyleFactory.create('windows'))
        self.ui.treeView_left_wheel_show.setStyle(QStyleFactory.create('windows'))
        # 完全展开
        # self.ui.treeView_left_wheel_control.expandAll()
        self.ui.treeView_left_wheel_show.expandAll()
        pass

    @staticmethod
    def init_tree_right_wheel_control(model):
        item = QStandardItem('控制')
        model.appendRow(item)
        # model.setItem(0, 1, QStandardItem('[Object]'))
        # 添加子条目
        item_child = QStandardItem('速度m/s')
        item.appendRow(item_child)
        item.setChild(0, 1, QStandardItem(str(0)))
        # 添加子条目
        # item_child = QStandardItem('转向(0/1)')
        # item.appendRow(item_child)
        # item.setChild(1, 1, QStandardItem(str(0)))
        # 添加子条目
        item_child = QStandardItem('运行周期s')
        item.appendRow(item_child)
        item.setChild(1, 1, QStandardItem(str(0)))
        item.child(1, 1).setEnabled(False)
        pass

    @staticmethod
    def init_tree_right_wheel_show(model):
        item = QStandardItem('右驱动轮状态')
        model.appendRow(item)
        # model.setItem(0, 1, QStandardItem('[Object]'))

        # 添加子条目
        # item_child = QStandardItem('转向(0反1正)')
        # item.appendRow(item_child)
        # item.setChild(0, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('速度m/s')
        item.appendRow(item_child)
        item.setChild(0, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('电流mA')
        item.appendRow(item_child)
        item.setChild(1, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('扭矩')
        item.appendRow(item_child)
        item.setChild(2, 1, QStandardItem('[Object]'))

        # 添加子条目
        item_child = QStandardItem('里程计')
        item.appendRow(item_child)
        item.setChild(3, 1, QStandardItem('[Object]'))
        # 添加子条目
        item_child = QStandardItem('错误代码')
        item.appendRow(item_child)
        item.setChild(4, 1, QStandardItem('[Object]'))
        pass

    def init_tab_motor_group_right_wheel(self):
        self.right_driver_model_control = QStandardItemModel(self.ptr)
        self.right_driver_model_control.setHorizontalHeaderLabels(['item', 'value'])
        self.right_driver_model_show = QStandardItemModel(self.ptr)
        self.right_driver_model_show.setHorizontalHeaderLabels(['item', 'value'])
        self.init_tree_right_wheel_control(self.right_driver_model_control)
        self.init_tree_right_wheel_show(self.right_driver_model_show)
        # self.ui.treeView_right_wheel_control.setModel(self.right_driver_model_control)
        self.ui.treeView_right_wheel_show.setModel(self.right_driver_model_show)
        # 调整第一列的宽度
        # self.ui.treeView_right_wheel_control.header().resizeSection(0, 160)
        # self.ui.treeView_right_wheel_control.header().resizeSection(1, 70)
        self.ui.treeView_right_wheel_show.header().resizeSection(0, 160)
        self.ui.treeView_right_wheel_show.header().resizeSection(1, 70)
        # 设置成有虚线连接的方式
        # self.ui.treeView_right_wheel_control.setStyle(QStyleFactory.create('windows'))
        self.ui.treeView_right_wheel_show.setStyle(QStyleFactory.create('windows'))
        # 完全展开
        # self.ui.treeView_right_wheel_control.expandAll()
        self.ui.treeView_right_wheel_show.expandAll()

    # update UI component
    def update_left_driver(self, value, child_row, child_col):
        parent_item = self.left_driver_model_show.item(0)
        parent_item.child(child_row, child_col).setText(str(value))

    def update_right_driver(self, value, child_row, child_col):
        parent_item = self.right_driver_model_show.item(0)
        parent_item.child(child_row, child_col).setText(str(value))
